package com.wqm;

import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
//import com.baomidou.mybatisplus.generator.config.InjectionConfig;
import com.baomidou.mybatisplus.generator.InjectionConfig;
import com.baomidou.mybatisplus.generator.config.*;
import com.baomidou.mybatisplus.generator.config.converts.MySqlTypeConvert;
import com.baomidou.mybatisplus.generator.config.po.TableInfo;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import com.baomidou.mybatisplus.generator.engine.VelocityTemplateEngine;
import com.baomidou.mybatisplus.generator.keywords.MySqlKeyWordsHandler;

import java.util.*;

/**
 * @author: wangqinmin
 * @date : 2020/10/24
 * @description: 仰天大笑出门去，我辈岂是蓬蒿人
 */
public class CodeGenerator2020 implements Config {

    /**
     * 循环数据库表
     */
    public void run() {
        for (int i = 0; i < DATABASE_TABLE_NAMES.length; i++) {
            if (i == DATABASE_TABLE_NAMES.length - 1) {
                // 生成代码，并执行-->是否打开文件夹操作
                runCodeGenerator(DATABASE_TABLE_NAMES[i], OPEN);
            } else {
                // 生成代码
                runCodeGenerator(DATABASE_TABLE_NAMES[i], false);
            }
        }
    }

    /**
     * 开始生成代码
     */
    public void runCodeGenerator(String tableName, boolean open) {
        AutoGeneratorProxy autoGenerator = new AutoGeneratorProxy();
        autoGenerator.setCfg(getInjectionConfig(tableName));
        autoGenerator.setTemplate(getTemplateConfig());
        autoGenerator.setPackageInfo(getPackageConfig());
        autoGenerator.setGlobalConfig(getGlobalConfig(open));
        autoGenerator.setDataSource(getDataSourceConfig());
        autoGenerator.setStrategy(getStrategyConfig(tableName));
        autoGenerator.setTemplateEngine(new VelocityTemplateEngine());
        autoGenerator.execute();
    }


    /**
     * 为自定义模板设置属性
     *
     * @param
     * @return
     */
    public InjectionConfig getInjectionConfig(String tableName) {
        // 获取自定义模板引擎
        List<FileOutConfig> fileOutConfigList = getFileOutConfigList();
        InjectionConfig cfg = new InjectionConfig() {
            @Override
            public void initMap() {
                Map<String, Object> map = new HashMap<>();
                // 为模板自定义属性,属性名必须大写开头
                map.put("IdParamPackage", SUPER_ID_PARAM);
                map.put("SuperEntityPackage", SUPER_ENTITY);
                map.put("QueryParamPackage", SUPER_QUERY_PARAM);
                map.put("QueryParamClass", "QueryParam");
                map.put("IDVoPackage", SUPER_ID_VO);
                map.put("IDVoClass", "IDVo");
                map.put("ControllerSuffix", PACKAGE_CONTROLLER[1]);
                map.put("ControllerPrefix", PACKAGE_CONTROLLER[0]);
                map.put("ServiceSuffix", PACKAGE_SERVICE[1]);
                map.put("ServicePrefix", PACKAGE_SERVICE[0]);
                map.put("ServiceImplSuffix", PACKAGE_SERVICE_IMPL[1]);
                map.put("ServiceImplPrefix", PACKAGE_SERVICE_IMPL[0]);
                map.put("MapperSuffix", PACKAGE_MAPPER[1]);
                map.put("MapperPrefix", PACKAGE_MAPPER[0]);
                map.put("EntitySuffix", PACKAGE_ENTITY[1]);
                map.put("EntityName", underlineToPascal(standardEntityName(tableName)));
                map.put("EntityPrefix", PACKAGE_ENTITY[0]);
                map.put("ParamSuffix", PACKAGE_PARAM[1]);
                map.put("ParamPrefix", PACKAGE_PARAM[0]);

//                map.put("daoEntity",dao_entity[0]);
                map.put("remoteBaseBo", package_remote_base_bo[0]);
                map.put("remoteBaseDto", package_remote_base_dto[0]);
                map.put("remoteExtBo", package_remote_ext_bo[0]);
                map.put("remoteExtDto", package_remote_ext_dto[0]);
                map.put("remoteBo", package_remote_bo[0]);
                map.put("remoteBoSuffix", package_remote_bo[1]);
                map.put("remoteDto", package_remote_dto[0]);
                map.put("remoteDtoSuffix", package_remote_dto[1]);

                map.put("VoSuffix", PACKAGE_VO[1]);
                map.put("VoPrefix", PACKAGE_VO[0]);
                map.put("DatabaseTable", "");
                map.put("ResponsePackage", PACKAGE_RESPONSE[0]);
                map.put("ResponseClass", PACKAGE_RESPONSE[1]);
                map.put("Parent", package_parent);
                map.put("LowerCaseEntityName", underlineToCamel(standardEntityName(tableName)));
                map.put("Success_return_method", SUCCESS_RETURN_METHOD);
                this.setMap(map);
            }
        };
        cfg.setFileOutConfigList(fileOutConfigList);
        return cfg;
    }


    public static void main(String[] args) {

        /**
         *     String remotePojo_base = "remotepojo/base/";
         *     String remotePojo_ext = "remotepojo/ext/";
         *
         *
         *     String dao = template + "dao/entity" + vm;
         *
         *     String remotePojo_base_bo = template + remotePojo_base + "bo/entity" + vm;
         *     String remotePojo_base_dto = template + remotePojo_base + "dto/entity" + vm;
         *     String remotePojo_ext_bo = template + remotePojo_ext + "bo/entity" + vm;
         *     String remotePojo_ext_dto = template + remotePojo_ext + "dto/entity" + vm;
         */
//        String path = CODE_GENERATION_PATH + "/main/java" + underPackageNameBackSlash(package_parent + "." + package_module_name + "." + "hello")
//        +"/" + "%s" + "wo" + ".java";
        // /Users/wangqinmin/code/java/javacode/edit/20230325/communism/communism-code-generator/src/main/java/com/tiantian/hello/%swo.java
        // /src/main/java/com/tiantian/hello/%swo.java
        ///src/main/java/com/tiantian/dao/%snull.java
        ///src/main/java/com/tiantian/entity/%snull.java
//        hello =
//        System.out.println(path);
        /**
         * dao
         *  src/main/java/com/tiantian/dao/Example.java
         * remotepojo
         *  src/main/java/com/tiantian/remotepojo/base/bo/BaseExampleBo.java
         *  src/main/java/com/tiantian/remotepojo/base/dto/BaseExampleDto.java
         *  src/main/java/com/tiantian/remotepojo/ext/bo/ExtExampleBo.java
         *  src/main/java/com/tiantian/remotepojo/ext/dto/ExtExampleDto.java
         */
        String path = CODE_GENERATION_PATH + "/main/java" + underPackageNameBackSlash(package_parent + "." + package_module_name + "." + "remotepojo.base.bo")
                + "/" + "%s%s%s" + ".java";
        System.out.println(path);
        String filePath = String.format(path, "Base", underlineToPascal(standardEntityName("example")), "Bo");
        System.err.println(filePath);


    }

    /**
     * 根据模板引擎，生成文件及文件路径
     *
     * @return
     */
    public List<FileOutConfig> getFileOutConfigList() {
        // 封装模本名称、及对应包名相对地址
        Map<String, String[]> templatesNames = new HashMap<>();
//        templatesNames.put(TEMPLATE_CONTROLLER, PACKAGE_CONTROLLER);
//        templatesNames.put(TEMPLATE_SERVICE, PACKAGE_SERVICE);
//        templatesNames.put(TEMPLATE_SERVICE_IMPL, PACKAGE_SERVICE_IMPL);
//        templatesNames.put(TEMPLATE_MAPPER, PACKAGE_MAPPER);
//        templatesNames.put(TEMPLATE_XML, PACKAGE_MAPPER_XML);
//        templatesNames.put(TEMPLATE_ENTITY_JAVA, PACKAGE_ENTITY);
//        templatesNames.put(TEMPLATE_PARAM, PACKAGE_PARAM);
//        templatesNames.put(TEMPLATE_VO, PACKAGE_VO);

        // 实体类
//        templatesNames.put(dao, new String[]{"dao", "", ""});
        // 远程实体类
        templatesNames.put(remotePojo_base_bo, new String[]{"remotepojo.base.bo", "Base", "Bo"});
        templatesNames.put(remotePojo_base_dto, new String[]{"remotepojo.base.dto", "Base", "Dto"});
        templatesNames.put(remotePojo_ext_bo, new String[]{"remotepojo.ext.bo", "Ext", "Bo"});
        templatesNames.put(remotePojo_ext_dto, new String[]{"remotepojo.ext.dto", "Ext", "Dto"});

        templatesNames.put(service_base, new String[]{"service.base", "Base", "Service"});
        templatesNames.put(service_dto, new String[]{"service.ext", "Ext", "Service"});

        templatesNames.put(serviceImpl_base_serviceImpl, new String[]{"webapi.api.base.serviceimpl", "Base", "ServiceImpl"});
        templatesNames.put(serviceImpl_ext_serviceImpl, new String[]{"webapi.api.ext.serviceimpl", "Ext", "ServiceImpl"});

        templatesNames.put(mapper, new String[]{"webapi.mapper", "", "Mapper"});
        templatesNames.put(mapperXml, new String[]{"webapi.mapper", "", "Mapper.xml"});

        templatesNames.put(base_web_controller, new String[]{"webapi.api.base.web.controller", "Base", "Controller"});
        templatesNames.put(ext_web_controller, new String[]{"webapi.api.ext.web.controller", "Ext", "Controller"});

        List<FileOutConfig> fileOutConfigs = new ArrayList<>();

        for (String templateName : templatesNames.keySet()) {
            String path = CODE_GENERATION_PATH + "/main/java" + underPackageNameBackSlash(package_parent + "." + package_module_name + "." + templatesNames.get(templateName)[0])
                    + "/" + "%s%s%s" + ".java";

            if (templateName.equals(dao)) {
                setTemplateData(fileOutConfigs, templateName, path, templatesNames.get(templateName));

            } else if (templateName.equals(remotePojo_base_bo)) {
                setTemplateData(fileOutConfigs, templateName, path, templatesNames.get(templateName));
            } else if (templateName.equals(remotePojo_base_dto)) {
                setTemplateData(fileOutConfigs, templateName, path, templatesNames.get(templateName));
            } else if (templateName.equals(remotePojo_ext_bo)) {
                setTemplateData(fileOutConfigs, templateName, path, templatesNames.get(templateName));
            } else if (templateName.equals(remotePojo_ext_dto)) {
                setTemplateData(fileOutConfigs, templateName, path, templatesNames.get(templateName));

            } else if (templateName.equals(service_base)) {
                setTemplateData(fileOutConfigs, templateName, path, templatesNames.get(templateName));
            } else if (templateName.equals(service_dto)) {
                setTemplateData(fileOutConfigs, templateName, path, templatesNames.get(templateName));
            } else if (templateName.equals(serviceImpl_base_serviceImpl)) {
                setTemplateData(fileOutConfigs, templateName, path, templatesNames.get(templateName));
            } else if (templateName.equals(serviceImpl_ext_serviceImpl)) {
                setTemplateData(fileOutConfigs, templateName, path, templatesNames.get(templateName));

            } else if (templateName.equals(mapper)) {
                setTemplateData(fileOutConfigs, templateName, path, templatesNames.get(templateName));
            } else if (templateName.equals(mapperXml)) {
                path = CODE_GENERATION_PATH + "/main/java" + underPackageNameBackSlash(package_parent + "." + package_module_name + "." + templatesNames.get(templateName)[0])
                        + "/" + "%s%s%s";
                setTemplateData(fileOutConfigs, templateName, path, templatesNames.get(templateName));

            }else if (templateName.equals(base_web_controller)) {
                setTemplateData(fileOutConfigs, templateName, path, templatesNames.get(templateName));
            }else if (templateName.equals(ext_web_controller)) {
                setTemplateData(fileOutConfigs, templateName, path, templatesNames.get(templateName));
            } else {

            }

//            // todo 修改文件生成名称和路径
//            else if (!templateName.contains("mapper.xml.vm" ) && !templateName.contains("aservice.java.vm" )) {
//                fileOutConfigs.add(new FileOutConfig(templateName) {
//                    @Override
//                    public String outputFile(TableInfo tableInfo) {
//                        String s = CODE_GENERATION_PATH + "/main/java" + underPackageNameBackSlash(package_parent + StringPool.DOT + package_module_name + StringPool.DOT + templatesNames.get(templateName)[0])
//                                + StringPool.SLASH + underlineToPascal(standardEntityName(tableInfo.getName())) + templatesNames.get(templateName)[1] + StringPool.DOT_JAVA;
//                        System.err.println(s);
//                        return s;
//                    }
//                });
//            } else if (templateName.contains("aservice.java.vm" )) {
//                fileOutConfigs.add(new FileOutConfig(templateName) {
//                    @Override
//                    public String outputFile(TableInfo tableInfo) {
//                        String s = CODE_GENERATION_PATH + "/main/java" + underPackageNameBackSlash(package_parent + StringPool.DOT + package_module_name + StringPool.DOT + templatesNames.get(templateName)[0])
//                                + StringPool.SLASH + "I" + underlineToPascal(standardEntityName(tableInfo.getName())) + templatesNames.get(templateName)[1] + StringPool.DOT_JAVA;
//                        System.err.println(s);
//                        return s;
//                    }
//                });
//            } else {
//                fileOutConfigs.add(new FileOutConfig(templateName) {
//                    @Override
//                    public String outputFile(TableInfo tableInfo) {
//                        String s = CODE_GENERATION_PATH + "/main/resources/" + package_module_name + PACKAGE_MAPPER[1] + StringPool.SLASH +
//                                underlineToPascal(standardEntityName(tableInfo.getName())) + templatesNames.get(templateName)[1];
//                        System.err.println(s);
//                        return s;
//                    }
//                });
//            }

        }
        return fileOutConfigs;
    }

    private static void setTemplateData(List<FileOutConfig> fileOutConfigs, String templateName, String path, String[] entityInfo) {
        // todo new FileOutConfig(templateName)中指定模版存在 路径
        fileOutConfigs.add(new FileOutConfig(templateName) {
            @Override
            public String outputFile(TableInfo tableInfo) {
                // 指定使用模版引擎后，代码文件输出位置
                String filePath = String.format(path, entityInfo[1], underlineToPascal(standardEntityName(tableInfo.getName())), entityInfo[2]);
                System.err.println(filePath);
                return filePath;
            }
        });
    }


    /**
     * 项目-包名-相关配置
     *
     * @return
     */
    public PackageConfig getPackageConfig() {
        PackageConfig packageConfig = new PackageConfig();
        packageConfig.setParent(package_parent);
        packageConfig.setModuleName(package_module_name);
        packageConfig.setController(PACKAGE_CONTROLLER[0]);
        packageConfig.setEntity(PACKAGE_ENTITY[0]);
        packageConfig.setMapper(PACKAGE_MAPPER[0]);
        packageConfig.setService(PACKAGE_SERVICE[0]);
        packageConfig.setServiceImpl(PACKAGE_SERVICE_IMPL[0]);
        packageConfig.setXml(PACKAGE_MAPPER_XML[0]);
        // 指定生成文件目录
        String pathPrefix = CODE_GENERATION_PATH + "/main/java" + underPackageNameBackSlash(package_parent) + underPackageNameBackSlash(package_module_name);
        Map<String, String> map = new HashMap<>();
        map.put("controller_path", pathPrefix + underPackageNameBackSlash(PACKAGE_CONTROLLER[0]));
        map.put("service_path", pathPrefix + underPackageNameBackSlash(PACKAGE_SERVICE[0]));
        map.put("service_impl_path", pathPrefix + underPackageNameBackSlash(PACKAGE_SERVICE_IMPL[0]));
        map.put("mapper_path", pathPrefix + underPackageNameBackSlash(PACKAGE_MAPPER[0]));
        map.put("xml_path", CODE_GENERATION_PATH + "/main/resources/mapper");
        map.put("entity_path", pathPrefix + underPackageNameBackSlash(PACKAGE_ENTITY[0]));
        map.put("param_path", pathPrefix + underPackageNameBackSlash(PACKAGE_PARAM[0]));
        map.put("vo_path", pathPrefix + underPackageNameBackSlash(PACKAGE_VO[0]));
        packageConfig.setPathInfo(map);
        return packageConfig;
    }

    /**
     * 数据库-相关配置
     *
     * @return
     */
    public DataSourceConfig getDataSourceConfig() {
        DataSourceConfig dataSourceConfig = new DataSourceConfig();
        dataSourceConfig.setDriverName(DATABASE_DRIVER_NAME);
        dataSourceConfig.setUrl(DATABASE_URL);
        dataSourceConfig.setUsername(DATABASE_USER_NAME);
        dataSourceConfig.setPassword(DATABASE_PASS_WORD);
        // PostgreSQL方案
        //  dataSourceConfig.setSchemaName();
        // 自定义当前表的信息（不设置则直接查询数据库）
//          dataSourceConfig.setDbQuery(new MySqlQuery());
        dataSourceConfig.setDbType(DbType.MYSQL);
        // 关键字格式化
        dataSourceConfig.setKeyWordsHandler(new MySqlKeyWordsHandler());
        // 全局字段类型转换
        // dataSourceConfig.setTypeConvert(new MySqlTypeConvert());
        return dataSourceConfig;
    }

    /**
     * 策略配置项
     *
     * @return
     */
    public StrategyConfig getStrategyConfig(String tableName) {
        StrategyConfig strategyConfig = new StrategyConfig();
        // 生成 @RestController 注解
        strategyConfig.setRestControllerStyle(REST_CONTROLLER_ANNOTATION);
        strategyConfig.setSuperControllerClass(SUPER_CONTROLLER);
        // 该值为：实体类继承的父类的包名 , 该值指定后会自动解析出类名
        strategyConfig.setSuperEntityClass(SUPER_ENTITY);
        strategyConfig.setSuperServiceClass(SUPER_SERVICE);
        strategyConfig.setSuperServiceImplClass(SUPER_SERVICE_IMPL);
        strategyConfig.setSuperMapperClass(SUPER_MAPPER);
        strategyConfig.setVersionFieldName(VERSION_FIELD_NAME);
        strategyConfig.setLogicDeleteFieldName(LOGIC_DELETE_FIELD_NAME);
        strategyConfig.setEntityLombokModel(ENTITY_LOMBOK_MODEL);
        strategyConfig.setEntityTableFieldAnnotationEnable(ENTITY_FIELD_ANNOTATION_ENABLE);
        // 驼峰转连字符
        strategyConfig.setControllerMappingHyphenStyle(CONTROLLER_MAPPING_HYPHEN_STYLE);
        strategyConfig.setInclude(tableName);
        strategyConfig.setNaming(NamingStrategy.underline_to_camel);
        strategyConfig.setColumnNaming(NamingStrategy.underline_to_camel);
        return strategyConfig;
    }


    /**
     * 模板路径配置
     *
     * @return
     */
    public TemplateConfig getTemplateConfig() {
        TemplateConfig templateConfig = new TemplateConfig();
        templateConfig.setController(TEMPLATE_CONTROLLER);
        templateConfig.setEntity(TEMPLATE_ENTITY_JAVA);
        templateConfig.setService(TEMPLATE_SERVICE);
        templateConfig.setServiceImpl(TEMPLATE_SERVICE_IMPL);
        templateConfig.setMapper(TEMPLATE_MAPPER);
        templateConfig.setXml(TEMPLATE_XML);
        return templateConfig;
    }


    /**
     * 全局配置
     */
    public GlobalConfig getGlobalConfig(boolean open) {
        GlobalConfig globalConfig = new GlobalConfig();
        // 生成文件的输出目录【默认 D 盘根目录
        globalConfig.setOutputDir(CODE_GENERATION_PATH);
        // 是否覆盖已有文件
        globalConfig.setFileOverride(FILE_OVERRIDE);
        // 是否打开输出目录
        globalConfig.setOpen(open);
        // 是否在xml中添加二级缓存配置
        globalConfig.setEnableCache(ENABLE_CACHE);
        // 开发人员
        globalConfig.setAuthor(AUTHOR);
        // 开启 Kotlin 模式 (默认false)
        globalConfig.setKotlin(false);
        // 开启 swagger2 模式
        globalConfig.setSwagger2(SWAGGER2);
//        globalConfig.setOpenApi3(OpenApi3);
        // 开启 ActiveRecord 模式
        globalConfig.setActiveRecord(ACTIVE_RECORD);
        // 开启 BaseResultMap
        globalConfig.setBaseResultMap(BASE_RESULT_MAP);
        // 时间类型对应策略
        globalConfig.setDateType(DATA_TYPE);
        // 开启 baseColumnList
        globalConfig.setBaseColumnList(BASE_COLUMN_LIST);
        // 定义主键类型
        globalConfig.setIdType(ID_TYPE);
        return globalConfig;
    }


    /**
     * <p>
     * 包名转地址名
     * </p>
     * 例如：com.wang.controller 转为：/com/wang/controller
     *
     * @param packageName
     */
    public static String underPackageNameBackSlash(String packageName) {
        if (StringUtils.isBlank(packageName)) {
            return null;
        }
        StringBuilder builder = new StringBuilder(packageName);
        builder.insert(0, StringPool.SLASH);
        return builder.toString().replace(StringPool.DOT, "/");
    }

    /**
     * uUser
     *
     * @param underline
     * @return
     */
    public static String underlineToCamel(String underline) {
        if (org.apache.commons.lang3.StringUtils.isNotBlank(underline)) {
            return NamingStrategy.underlineToCamel(underline);
        }
        return null;
    }


    /**
     * 驼峰模式   UUser
     *
     * @param underline
     * @return
     */
    public static String underlineToPascal(String underline) {
        if (StringUtils.isNotBlank(underline)) {
            return NamingStrategy.capitalFirst(NamingStrategy.underlineToCamel(underline));
        }
        return null;
    }

    /**
     * 去除数据库表名前缀
     *
     * @param tableName
     * @return
     */
    public static String standardEntityName(String tableName) {
        // 去重
        Set<String> entityName = new HashSet<>();
        String[] removeTablePrefix = DATABASE_REMOVE_PREFIX;
        if (removeTablePrefix.length == 0) {
            return tableName;
        }

        for (String tablePrefix : removeTablePrefix) {
            if (tableName.contains(tablePrefix)) {
                if (tableName.startsWith(tablePrefix)) {
                    return tableName.replace(tablePrefix, "");
                } else {
                    entityName.add(tableName);
                }
            } else {
                entityName.add(tableName);
            }
        }
        return (String) entityName.toArray()[0];
    }

}
